package cn.android666.nopreviewcamera

import android.opengl.EGL14
import android.opengl.EGLConfig
import android.opengl.EGLContext
import android.opengl.EGLDisplay
import android.opengl.EGLExt
import android.opengl.EGLSurface
import android.opengl.GLES20
import android.opengl.GLU
import android.view.Surface
import timber.log.Timber
import java.nio.ByteBuffer
import java.nio.ByteOrder

class YuvToSurfaceRenderer(private val inputSurface: Surface) {
    private var eglDisplay: EGLDisplay? = null
    private var eglContext: EGLContext? = null
    private var sharedContext: EGLContext? = null
    private var eglSurface: EGLSurface? = null

    // OpenGL 纹理 ID
    private var yTextureId = 0
    private var uvTextureId = 0
    private var program = 0

    // 当前帧的宽高
    private var frameWidth = 0
    private var frameHeight = 0

    // Y 分量和 UV 分量的数据缓冲区
    private var yBuffer: ByteBuffer? = null
    private var uvBuffer: ByteBuffer? = null

    /** 顶点着色器代码 */
    private val vertexShaderCode = """
        attribute vec4 aPosition; // 顶点位置
        attribute vec2 aTexCoord; // 纹理坐标
        varying vec2 vTexCoord;   // 传递给片元着色器
        void main() {
            gl_Position = aPosition;
            vTexCoord = aTexCoord;
        }
    """.trimIndent()

    /** 片元着色器代码 */
    private val fragmentShaderCode = """
        precision mediump float;
        varying vec2 vTexCoord;
        uniform sampler2D yTexture;
        uniform sampler2D uvTexture;

        void main() {
            float y = texture2D(yTexture, vTexCoord).r;   // Y分量
            vec2 uv = texture2D(uvTexture, vTexCoord).ra; // VU分量
            float v = uv.x - 0.5;
            float u = uv.y - 0.5;

            // YUV 转 RGB
            float r = y + 1.403 * v;
            float g = y - 0.344 * u - 0.714 * v;
            float b = y + 1.770 * u;
            gl_FragColor = vec4(r, g, b, 1.0); // 创建一个4分量的向量，代表 RGBA 颜色，最后一个参数1.0表示透明度为完全不透明
        }
    """.trimIndent()

    init {
        setupEgl()
        setupGl()
    }

    private fun setupEgl() {
        // 初始化 EGL
        eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)
        if (eglDisplay == EGL14.EGL_NO_DISPLAY) {
            throw RuntimeException("Unable to get EGL14 display")
        }

        val version = IntArray(2)
        if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) {
            throw RuntimeException("Unable to initialize EGL14")
        }

        // 配置 EGL
        val attribList = intArrayOf(
            EGL14.EGL_RED_SIZE, 8,
            EGL14.EGL_GREEN_SIZE, 8,
            EGL14.EGL_BLUE_SIZE, 8,
            EGL14.EGL_ALPHA_SIZE, 8,
            EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
            EGL14.EGL_NONE
        )

        val configs = arrayOfNulls<EGLConfig>(1)
        val numConfigs = IntArray(1)
        if (!EGL14.eglChooseConfig(eglDisplay, attribList, 0, configs, 0, configs.size, numConfigs, 0)) {
            throw RuntimeException("Unable to choose EGL config")
        }

        // 创建 EGL 上下文
        val contextAttribs = intArrayOf(
            EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL14.EGL_NONE
        )

        eglContext = EGL14.eglCreateContext(eglDisplay, configs[0], EGL14.EGL_NO_CONTEXT, contextAttribs, 0)
        sharedContext = EGL14.eglCreateContext(eglDisplay, configs[0], eglContext, contextAttribs, 0)

        if (eglContext == null || eglContext == EGL14.EGL_NO_CONTEXT) {
            throw RuntimeException("Failed to create EGL context")
        }

        // 创建 EGL Surface
        val surfaceAttribs = intArrayOf(EGL14.EGL_NONE)
        eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, configs[0], inputSurface, surfaceAttribs, 0)
        if (eglSurface == null || eglSurface == EGL14.EGL_NO_SURFACE) {
            throw RuntimeException("Failed to create EGL surface")
        }

        // 绑定 EGL 上下文和 Surface
        if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
            throw RuntimeException("Failed to make EGL context current")
        } else {
            Timber.i("init bind: ${Thread.currentThread().name}")
        }
    }

    private fun setupGl() {
        // 设置清除颜色为黑色
        GLES20.glClearColor(0f, 0f, 0f, 1f)

        // 创建并链接 shader 程序
        program = createProgram(vertexShaderCode, fragmentShaderCode)

        // 创建两个纹理：Y 和 UV
        yTextureId = createTexture()
        uvTextureId = createTexture()
    }

    var isFirst = true

    /** 更新一帧的 NV21 数据（Y + VU）并渲染到 Surface */
    fun renderFrame(nv21: ByteArray, width: Int, height: Int) {
        // 绑定 EGL 上下文和 Surface
        if (EGL14.eglGetCurrentContext() == EGL14.EGL_NO_CONTEXT) {
            Timber.i("NoContext...")
            if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
                throw RuntimeException("Failed to make EGL context current")
            } else {
                Timber.i("renderFrame bind: ${Thread.currentThread().name}")
            }
        } else {
            Timber.i("HasContext...")
        }

        frameWidth = width
        frameHeight = height

        val ySize = width * height
        val uvSize = width * height / 2

        // 分配缓冲区（如果还没分配或大小变化）
        if (yBuffer == null || yBuffer!!.capacity() != ySize)
            yBuffer = ByteBuffer.allocateDirect(ySize)
        if (uvBuffer == null || uvBuffer!!.capacity() != uvSize)
            uvBuffer = ByteBuffer.allocateDirect(uvSize)

        // 填充 Y 缓冲区
        yBuffer!!.clear()
        yBuffer!!.put(nv21, 0, ySize)
        yBuffer!!.position(0)

        // 填充 UV 缓冲区（NV21 是交错的 VU）
        uvBuffer!!.clear()
        uvBuffer!!.put(nv21, ySize, uvSize)
        uvBuffer!!.position(0)

        // 渲染到 Surface
        renderToSurface()
    }

    private fun renderToSurface() {
        // 没有有效数据就跳过渲染
        if (frameWidth == 0 || frameHeight == 0 || yBuffer == null || uvBuffer == null) return

        // 清屏
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

        // 使用编译好的 shader 程序
        GLES20.glUseProgram(program)

        // 上传 Y 分量到纹理 0
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureId)
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, frameWidth, frameHeight, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer)

        // 上传 UV 分量到纹理 1（注意：是 VU 顺序）
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uvTextureId)
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE_ALPHA, frameWidth / 2, frameHeight / 2, 0, GLES20.GL_LUMINANCE_ALPHA, GLES20.GL_UNSIGNED_BYTE, uvBuffer)

        // 绘制全屏矩形
        drawQuad(program)

        val presentationTimeNs = System.nanoTime()
        EGLExt.eglPresentationTimeANDROID(eglDisplay, eglSurface, presentationTimeNs)

        // 交换缓冲区，将渲染结果提交到 Surface
        EGL14.eglSwapBuffers(eglDisplay, eglSurface)
        if (eglDisplay == EGL14.EGL_NO_DISPLAY ||
            eglSurface == EGL14.EGL_NO_SURFACE ||
            eglContext == EGL14.EGL_NO_CONTEXT) {
            Timber.e("EGL资源已提前销毁111")
            return
        }
    }

    fun release() {
        if (eglDisplay == EGL14.EGL_NO_DISPLAY ||
            eglSurface == EGL14.EGL_NO_SURFACE ||
            eglContext == EGL14.EGL_NO_CONTEXT) {
            Timber.e("EGL资源已提前销毁222")
            return
        }

        // 确保当前线程有EGL上下文（否则删除操作无效）
        // 强制绑定原始EGL上下文（跨线程需确保线程安全）
        if (EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, eglContext)) {
            if (EGL14.eglGetCurrentContext() != EGL14.EGL_NO_CONTEXT) {
                Timber.i("Has Context")
                // 删除纹理
                val textures = intArrayOf(yTextureId, uvTextureId)
                GLES20.glDeleteTextures(2, textures, 0)

                // 删除着色器程序
                GLES20.glDeleteProgram(program)
            } else {
                Timber.i("No Context")
            }
        } else {
            Timber.i("release bind: ${Thread.currentThread().name}")
        }

        // 解绑当前上下文
        EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)

        // 销毁EGL资源
        EGL14.eglDestroySurface(eglDisplay, eglSurface)
        EGL14.eglDestroyContext(eglDisplay, eglContext)
        EGL14.eglTerminate(eglDisplay)

        val error = GLES20.glGetError()
        if (error != GLES20.GL_NO_ERROR) {
            Timber.i("Has Error: ${GLU.gluErrorString(error)}")
        } else {
            Timber.i("No Error")
        }
    }

    /** 创建一个 2D 纹理对象并设置基本参数 */
    private fun createTexture(): Int {
        val textureIds = IntArray(1)
        GLES20.glGenTextures(1, textureIds, 0)
        val texId = textureIds[0]
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE)
        return texId
    }

    /** 编译 shader 并链接生成 program */
    private fun createProgram(vertexSource: String, fragmentSource: String): Int {
        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource)
        val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource)

        val program = GLES20.glCreateProgram()
        GLES20.glAttachShader(program, vertexShader)
        GLES20.glAttachShader(program, fragmentShader)
        GLES20.glLinkProgram(program)

        // 检查链接状态
        val linkStatus = IntArray(1)
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0)
        if (linkStatus[0] == 0) {
            val error = GLES20.glGetProgramInfoLog(program)
            GLES20.glDeleteProgram(program)
            throw RuntimeException("Program link failed: $error")
        }
        return program
    }

    /** 加载并编译单个 shader（顶点或片元） */
    private fun loadShader(type: Int, shaderSource: String): Int {
        val shader = GLES20.glCreateShader(type)
        GLES20.glShaderSource(shader, shaderSource)
        GLES20.glCompileShader(shader)

        // 检查编译状态
        val compiled = IntArray(1)
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0)
        if (compiled[0] == 0) {
            val error = GLES20.glGetShaderInfoLog(shader)
            GLES20.glDeleteShader(shader)
            throw RuntimeException("Shader compile failed: $error")
        }
        return shader
    }

    /** 绘制一个矩形（全屏四顶点）用于显示纹理 */
    private fun drawQuad(program: Int) {
        val aPosition = GLES20.glGetAttribLocation(program, "aPosition")
        val aTexCoord = GLES20.glGetAttribLocation(program, "aTexCoord")
        val ySampler = GLES20.glGetUniformLocation(program, "yTexture")
        val uvSampler = GLES20.glGetUniformLocation(program, "uvTexture")

        // 顶点坐标 [-1, 1]，代表全屏
        val vertexCoords = floatArrayOf(
            -1f, -1f, // 左下
            1f, -1f,  // 右下
            -1f,  1f, // 左上
            1f,  1f   // 右上
        )

        // 纹理坐标 [0, 1]
        val texCoords = floatArrayOf(
            0f, 1f,   1f, 1f,
            0f, 0f,   1f, 0f
        )

        val vb = ByteBuffer.allocateDirect(vertexCoords.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer()
        vb.put(vertexCoords).position(0)

        val tb = ByteBuffer.allocateDirect(texCoords.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer()
        tb.put(texCoords).position(0)

        GLES20.glEnableVertexAttribArray(aPosition)
        GLES20.glVertexAttribPointer(aPosition, 2, GLES20.GL_FLOAT, false, 0, vb)

        GLES20.glEnableVertexAttribArray(aTexCoord)
        GLES20.glVertexAttribPointer(aTexCoord, 2, GLES20.GL_FLOAT, false, 0, tb)

        // 设置纹理采样器对应的纹理单元
        GLES20.glUniform1i(ySampler, 0)  // GL_TEXTURE0
        GLES20.glUniform1i(uvSampler, 1) // GL_TEXTURE1

        // 绘制两个三角形构成的矩形（GL_TRIANGLE_STRIP）
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)

        GLES20.glDisableVertexAttribArray(aPosition)
        GLES20.glDisableVertexAttribArray(aTexCoord)
    }
}